﻿using System;
using System.Linq;
using TinyEngine.Core.Entities.Parsers;
using TinyEngine.Core.Asset;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using TinyEngine.Core.Services;
using TinyEngine.Core.Renderer;
using TinyEngine.Core;
namespace TinyEngine.Core.Entities
{
    [TinyEngine.Core.Attributes.EntityParser(typeof(SpriteParser))]
    public class SpriteEntity : TinyEngine.Core.Entities.NullEntity, IAssetHolder<SpriteAsset>, IRenderable, IDebugRenderable, IUpdatable
    {
        public bool FlipHorizontal { get; set; }
        public bool FlipVertical { get; set; }
        public SpriteEntity()
        {
            this.Scale = 1;
            this.Tint = Color.White;
            this.SourceRectangle = null;
        }
        public bool Visible { get; set; }
        public float Scale { get; set; }
        public Texture2D Texture
        {
            get
            {
                if (this.Asset == null) return null;
                return this.Asset.Asset;
            }
        }

        public Color Tint { get; set; }

        private string assetName;

        public string AssetName
        {
            get { return assetName; }
            set 
            {
                if (assetName != value)
                {
                    assetName = value;
                    RefreshAsset();
                }
            }
        }

        private void RefreshAsset()
        {
            if (Asset != null)
            {
                Asset.Updated -= new Action<object>(Asset_Updated);
            }
            var asset = ServiceManager.GetService<AssetLibrary>().GetSprite(this.AssetName);
            this.Asset = asset;
            
            if (Asset != null)
            {
                Asset.Updated += new Action<object>(Asset_Updated);
            }

            UpdateInternalOffset();
            //this.Origin = new Vector2(this.Texture.Width / 2, this.Texture.Height / 2);
        }

        private void UpdateInternalOffset()
        {
            if (this.Texture != null)
                internalOffset = new Vector2(this.Texture.Width / 2, this.Texture.Height / 2);
        }

        void Asset_Updated(object obj)
        {
            if (this.Texture != null)
                UpdateInternalOffset();
        }

        public string AssetLocation { get; set; }

        public SpriteAsset Asset { get; set; }

        public virtual void DrawDebug(float elapsed)
        {
            var renderer = Services.ServiceManager.GetService<PrimitiveBatchService>();
            renderer.Batch.DrawBox(this.BoundingRectangle);
        }
        
        protected Vector2 internalOffset = Vector2.Zero;

        public float Rotation { get; set; }
        public float Layer { get; set; }
        public virtual void Draw(float elapsed)
        {
            var renderer = Services.ServiceManager.GetService<SpriteBatchService>();

            var origin = internalOffset;
            origin += this.Origin;
            
            renderer.Batch.Draw(
                            this.Texture,
                            this.Position.ToVector2(),
                            this.SourceRectangle,
                            this.Tint,
                            this.Rotation,
                            origin,
                            this.Scale,
                            GetSpriteEffects(),
                            this.Layer
                            );
    
        }

        protected SpriteEffects GetSpriteEffects()
        {
            var eff = SpriteEffects.None;
            if (this.FlipHorizontal)
                eff |= SpriteEffects.FlipHorizontally;
            if (this.FlipVertical)
                eff |= SpriteEffects.FlipVertically;
            return eff;
        }

        public Rectangle? SourceRectangle { get; set; }

        public Vector2 Origin { get; set; }

        public void CenterOrigin()
        {
            this.Origin = new Vector2(this.Texture.Width / 2, this.Texture.Height / 2);
            if (this.SourceRectangle != null)
            {
                this.Origin = new Vector2(this.SourceRectangle.Value.Width  / 2, this.SourceRectangle.Value.Height / 2);
            }
        }

        public override void PositionChanged()
        {   
            if (this.Texture == null) return;
            var rect = new Rectangle(
                (int)(this.Position.X - this.Origin.X - internalOffset.X),
                (int)(this.Position.Y - this.Origin.Y - internalOffset.Y),
                this.Texture.Width,
                this.Texture.Height);
            
            this.SetBounds( rect);
        }

        public override void CopyTo(object item)
        {
            base.CopyTo(item);

            var text = item as SpriteEntity;
            if (text == null)
                return;

            text.Visible = this.Visible;
            text.Tint = this.Tint;
            text.Origin = this.Origin;
            text.AssetName = AssetName;
        }

    }
}
